#pragma once
#include <core/sync/lock.h>

#include <string>
#include <unordered_map>
#include <vector>

#include "bondlib.h"
#include "qbprotocol/include/SSQBModel.h"

#define INVALID_CDC_VALUE -1e6
struct sCDCPrice {
  uint32_t m_nEstDate;             // 估值日期
  char m_sEstcleanprice[10];       // 估值净价
  char m_sEstPrice[10];            // 估值收益率		中债估值
  char m_sFrontEstcleanprice[10];  // 估值净价
  char m_sFrontEstPrice[10];       // 估值收益率		中债估值
  char m_sDuration[10];            // 中债估值久期
  sCDCPrice() {
    _InitializeString(m_sEstcleanprice);
    _InitializeString(m_sEstPrice);
    _InitializeString(m_sFrontEstcleanprice);
    _InitializeString(m_sFrontEstPrice);
    _InitializeString(m_sDuration);
    m_nEstDate = 0;
  }
};

class CBondCdcPriceUnit {
 public:
  CBondCdcPriceUnit();
  void Add(const int nPrcType, const xQBACDCPriceUnit_c& unit, bool bSpecial);
  bool GetEstimateElement(char* const estPrice, const int capacity,
                          const int nOptType, const int nPrcType = 0,
                          bool bYesterday = false) const;
  uint32_t GetEstimateDate() const;
  int GetSize() const;
  bool isSpecial() const;

 private:
  // [内存优化][scofined.qi]
  // key为CBondCDCPriceInfo::kEstOptionType,固定整数值
  // 处于节省内存,以及缓存行友好的考虑,使用vector替换哈希表
  struct KeyValue {
    int first;         // 取值为kEstOptionType
    sCDCPrice second;  //
  };
  class CDCPriceVec {
    std::vector<KeyValue> m_values;

   public:
    using iterator = std::vector<KeyValue>::iterator;
    using const_iterator = std::vector<KeyValue>::const_iterator;
    int size() const { return m_values.size(); }
    void clear() { m_values.clear(); }
    const_iterator end() const { return m_values.cend(); }
    const_iterator find(int optionType) const;
    iterator find(int optionType);
    void insert(int optionType, const sCDCPrice& price);
    sCDCPrice& operator[](int optionType);
  };
  typedef CDCPriceVec Container;
  Container m_mpBondCdc;
  bool m_bSpecial;  // 特殊估值
};

class S_BONDLIB_EXPORT CBondCDCPriceInfo {
 public:
  enum kEstOptionType {
    est_type_invalid = -2,  // 无效值
    est_type_combine = -1,  // 行权/到期， 外部提示辅助使用
    est_type_exercise,      // 行权中债估值
    est_type_expire,        // 到期中债估值
    est_type_null,
  };
  enum kPriceType {
    price_type_yield,     // 中债估值
    price_type_clean,     // 中债估值净价
    price_type_duration,  // 中债估值久期
    price_type_full,      // 中债估值全价
  };
  static CBondCDCPriceInfo& instance();

  qb::base::CSLock& GetMutex() { return m_mutex; }
  void ClearAll();
  void ClearNonSpecial();
  void ClearSpecial();
  void Add(const int nBondIndex, const xQBACDCPriceUnit_c& unit,
           bool bSpecial);  // 需要外部加锁
  bool isTodayDataValid(bool bSpec);

  // 获取单券昨日中债估值 bSingle=true时 行权>到期，bSingle=false时 行权+到期
  std::string GetCDCPriceYesterday(
      int& nOptType, const bool bIsCdcAuthValid, const int nBondIndex,
      const int nPrcType /* = CBondCDCPriceInfo::price_type_yield*/,
      bool bSingle /*=false*/);

  // 获取单券今日中债估值 bSingle=true时 行权>到期，bSingle=false时 行权+到期
  std::string GetCDCPriceToday(
      int& nOptType, const bool bIsCdcAuthValid, const int nBondIndex,
      const int nPrcType /* = CBondCDCPriceInfo::price_type_yield*/,
      bool bSingle /*=false*/);

  // 获取单券最新中债估值 bSingle=true时 行权>到期，bSingle=false时 行权+到期
  std::string GetCDCPriceLast(
      int& nOptType, const bool bIsCdcAuthValid, const int nBondIndex,
      const int nPrcType /* = CBondCDCPriceInfo::price_type_yield*/,
      bool bSingle /*=false*/);

  uint32_t GetEstimateDate(
      const int nBondIndex);  // 获取估值相关元素\净价 久期等，优先取行权估值
  std::string GetRelaEstimatePrice(
      const bool bIsCdcAuthValid, const int nBondIndex,
      const int nPrcType = 0 /*CBondCDCPriceInfo::price_type_yield*/,
      const char* pRef = nullptr, bool bYesterday = false);  // 简单获取中债估值
  double GetEstimatePriceGap(
      const bool bIsCdcAuthValid, const int nBondIndex,
      const int nPrcType = 0 /*CBondCDCPriceInfo::price_type_yield*/,
      bool bReverse = true, const char* pRef = nullptr,
      const double dRef = INVALID_CDC_VALUE, bool bYesterday = false,
      bool bForceExercise = false);  // 默认中债-price

  void GetExerciseAndMaturity(const bool bIsCdcAuthValid, const int nBondIndex,
                              double& dExercise, double& dMaturity);

  // 默认昨日中债-price,
  double GetYesterdayCDCPriceGap(
      const bool bIsCdcAuthValid, const int nBondIndex,
      const int nPrcType /*=CBondCDCPriceInfo::price_type_yield*/,
      bool bReverse /* = true*/, const char* pRef /* = nullptr*/,
      const double dRef /* = INVALID_CDC_VALUE*/,
      bool bForceExercise /* = false*/);

  // 默认昨日中债-price,
  double GetYesterdayCDCCleanPriceGap(
      const bool bIsCdcAuthValid, const int nBondIndex,
      const int nPrcType /*=CBondCDCPriceInfo::price_type_yield*/,
      bool bReverse /* = true*/, const char* pRef /* = nullptr*/,
      const double dRef /* = INVALID_CDC_VALUE*/, int exercise /*= -1*/);

  // 成交统计专用
  std::string GetCDCPriceYesterdayByOpt(
      int& nOptType, const bool bIsCdcAuthValid, const int nBondIndex,
      const int nOptTypeStart,
      const int nPrcType /* = CBondCDCPriceInfo::price_type_yield*/);

  static int GetCdcPrcType(const xQBACDCPriceUnit_c& unit);
  static bool IsPriceValid(const char* pPrc, bool bIsCdc = false);
  static std::string GetSplit();

 private:
  CBondCDCPriceInfo();
  ~CBondCDCPriceInfo() {}

 private:
  std::unordered_map<int, CBondCdcPriceUnit> m_mpCdcContainer;
  qb::base::CSLock m_mutex;
  unsigned int m_updateDate = 0;
  unsigned int m_updateDateSpec = 0;  // 特殊估值
};
